import prompts from "prompts";
import type { ArgumentsCamelCase } from "yargs";
import { join, basename } from "node:path";
import {
  readFileSync,
  existsSync,
  statSync,
  readdirSync,
  writeFileSync,
  appendFileSync,
  mkdirSync,
  rmSync,
} from "node:fs";
import chalk from "chalk";
import _upperFirst from "lodash.upperfirst";
import _camelCase from "lodash.camelcase";
import _kebabCase from "lodash.kebabcase";
import _template from "lodash.template";
import _get from "lodash.get";
import _lowerFirst from "lodash.lowerfirst";
import json5 from "json5";
import type { ConfigInfo } from "./template";
import { resolveTemplate } from "./template";
import { rootPath, configPath } from "./path.config";

export type ChildCmd = "add" | "remove";

/**
 * 获取配置信息
 */
const getConfig = (): ConfigInfo => {
  let cfg;
  const path = join(rootPath, configPath);
  if (existsSync(path)) {
    const cfgStr = readFileSync(path, "utf-8");
    cfg = json5.parse(cfgStr);
  }

  if (!cfg) {
    throw new Error("配置文件不存在");
  }

  return cfg;
};

const getSeries = async (cfg: ConfigInfo): Promise<string> => {
  const series =
    cfg?.series ||
    (
      await prompts({
        type: "text",
        name: "series",
        message: "请输入组件系列前缀",
        validate: (value) => {
          if (!value) {
            return "组件系列前缀不能为空";
          }
          return true;
        },
      })
    ).series;

  if (!series) {
    throw new Error("组件系列前缀不能为空");
  }
  return series;
};

const getSrc = async (cfg: ConfigInfo): Promise<string> => {
  const src =
    cfg?.src ||
    (
      await prompts({
        type: "text",
        name: "src",
        message: "请输入组件源码路径",
        initial: "src",
        validate: (value) => {
          if (!value) {
            return "组件源码路径不能为空";
          }
          return true;
        },
      })
    ).src;

  if (!src) {
    throw new Error("组件源码路径不能为空");
  }
  return src;
};

/**
 * 获取组件列表
 */
const getComponentList = ({
  src,
  entryAbsoluteSrc,
  entryTemplate,
}: {
  src: string;
  entryAbsoluteSrc: string;
  entryTemplate: string;
}): string[] => {
  const srcPath = join(rootPath, src);

  const stats = statSync(srcPath);

  let entryFileContent = "";
  if (existsSync(entryAbsoluteSrc)) {
    entryFileContent = readFileSync(entryAbsoluteSrc, "utf-8") || "";
  }

  if (!entryFileContent) {
    throw new Error("没有可以删除的文件");
  }

  if (stats.isDirectory()) {
    const files = readdirSync(srcPath);
    // console.log("files:", files);

    const template = _template(entryTemplate);

    const list = files
      .map((file) => {
        const filePath = join(srcPath, file);
        const stats = statSync(filePath);
        if (stats.isDirectory()) {
          // console.log("filePath:", filePath, basename(filePath));
          return basename(filePath);
        } else {
          return "";
        }
      })
      .filter((item) => {
        if (!item) {
          return false;
        }
        const allNameInfo = getAllNameInfo({ name: item });
        const res = template({
          ...allNameInfo,
          src,
          nameLowerFirst: _lowerFirst(allNameInfo.name),
        });
        // console.log("res:", res);
        return entryFileContent.includes(res);
      });

    if (list.length === 0) {
      throw new Error("组件列表为空");
    }
    return list;
  } else {
    throw new Error("组件源码路径不是目录");
  }
};

/**
 * 获取所有名称信息
 */
export const getAllNameInfo = ({
  name,
  series,
}: {
  name: string;
  series?: string;
}) => {
  const nameRes = _upperFirst(_camelCase(name));

  const seriesRes = series ? _upperFirst(_camelCase(series)) : "";

  const fullRes = series ? `${seriesRes}${nameRes}` : "";

  const cls = series ? _kebabCase(fullRes) : "";

  const dir = _kebabCase(name);

  // console.log(`
  //   series: ${seriesRes};
  //   name: ${nameRes};
  //   full: ${fullRes};
  //   cls: ${cls};
  //   dir: ${dir};
  // `);

  return {
    series: seriesRes,
    name: nameRes,
    full: fullRes,
    cls,
    dir,
  };
};

export const dealAdd = async ({
  argv,
  configInfo,
}: {
  argv: ArgumentsCamelCase;
  configInfo: ConfigInfo;
  src: string;
}) => {
  const series = await getSeries(configInfo);

  // console.log("series:", series);

  const name =
    argv.name ||
    (
      await prompts({
        type: "text",
        name: "name",
        message: "请输入组件名称",
        validate: (value) => {
          if (!value) {
            return "组件名称不能为空";
          }
          return true;
        },
      })
    ).name;

  // console.log("name:", name);

  if (!name) {
    throw new Error("组件名称不能为空");
  }

  const allNameInfo = getAllNameInfo({
    name,
    series,
  });

  console.log(allNameInfo);

  const data = resolveTemplate(
    configInfo,
    {
      ...allNameInfo,
      rootPath,
    },
    [
      "component.dir",
      "component.templateFilePath",
      "component.fileName",
      "component.entryTemplate",
      "component.entryPath",

      "type.dir",
      "type.templateFilePath",
      "type.fileName",
      "type.entryTemplate",
      "type.entryPath",

      "style.dir",
      "style.templateFilePath",
      "style.fileName",
      "style.varTemplate",
      "style.varPath",
      "style.entryTemplate",
      "style.entryPath",

      "example.dir",
      "example.templateFilePath",
      "example.fileName",
      "example.entryTemplate",
      "example.entryPath",
    ],
  );

  console.log(data);

  const { useTypeDir } = data;

  if (existsSync(data.componentFilePath)) {
    throw new Error("组件已存在");
  }

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    if (existsSync(data.typeFilePath)) {
      throw new Error("类型已存在");
    }
  }

  if (existsSync(data.styleFilePath)) {
    throw new Error("样式已存在");
  }

  if (existsSync(data.exampleFilePath)) {
    throw new Error("示例已存在");
  }

  mkdirSync(data.componentDirPath, { recursive: true });
  writeFileSync(data.componentFilePath, data.componentFileContent);

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    mkdirSync(data.typeDirPath, { recursive: true });
    writeFileSync(data.typeFilePath, data.typeFileContent);
  }

  mkdirSync(data.styleDirPath, { recursive: true });
  writeFileSync(data.styleFilePath, data.styleFileContent);

  mkdirSync(data.exampleDirPath, { recursive: true });
  writeFileSync(data.exampleFilePath, data.exampleFileContent);

  if (!existsSync(data.componentEntryFilePath)) {
    writeFileSync(data.componentEntryFilePath, "");
  }
  appendFileSync(
    data.componentEntryFilePath,
    data.componentEntryFileAddContent,
  );

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    if (!existsSync(data.typeEntryFilePath)) {
      writeFileSync(data.typeEntryFilePath, "");
    }
    appendFileSync(data.typeEntryFilePath, data.typeEntryFileAddContent);
  }

  if (!existsSync(data.styleEntryFilePath)) {
    writeFileSync(data.styleEntryFilePath, "");
  }
  appendFileSync(data.styleEntryFilePath, data.styleEntryFileAddContent);

  if (!existsSync(data.styleVarFilePath)) {
    writeFileSync(data.styleVarFilePath, "");
  }
  appendFileSync(data.styleVarFilePath, data.styleVarFileAddContent);

  if (!existsSync(data.exampleEntryFilePath)) {
    writeFileSync(data.exampleEntryFilePath, "");
  }
  appendFileSync(data.exampleEntryFilePath, data.exampleEntryFileAddContent);

  console.log(chalk.green("创建成功"));
};

export const dealRemove = async ({
  configInfo,
  src,
}: {
  argv: ArgumentsCamelCase;
  configInfo: ConfigInfo;
  src: string;
}) => {
  // 组件入口路径模板
  const componentEntryPathTemplate = _get(configInfo, "component.entryPath");

  // 组件入口路径
  const componentEntryPath = _template(componentEntryPathTemplate)({
    src,
  });

  const choices = getComponentList({
    src,
    entryAbsoluteSrc: join(rootPath, componentEntryPath),
    entryTemplate: configInfo.component.entryTemplate,
  }).map((item) => {
    return { title: item, value: item };
  });

  const { name } = await prompts({
    type: "select",
    name: "name",
    message: "请选择要删除的组件",
    choices,
  });

  console.log("name:", name);

  if (!name) {
    throw new Error("组件名称不能为空");
  }

  const allNameInfo = getAllNameInfo({
    name,
  });

  console.log(allNameInfo);

  const data = resolveTemplate(
    configInfo,
    {
      ...allNameInfo,
      rootPath,
    },
    [
      "component.dir",
      "component.templateFilePath",
      "component.fileName",
      "component.entryTemplate",
      "component.entryPath",

      "type.dir",
      "type.templateFilePath",
      "type.fileName",
      "type.entryTemplate",
      "type.entryPath",

      "style.dir",
      "style.templateFilePath",
      "style.fileName",
      "style.varTemplate",
      "style.varPath",
      "style.entryTemplate",
      "style.entryPath",

      "example.dir",
      "example.templateFilePath",
      "example.fileName",
      "example.entryTemplate",
      "example.entryPath",
    ],
  );

  console.log(data);

  const { useTypeDir } = data;

  if (!existsSync(data.componentFilePath)) {
    console.log(chalk.red("组件不存在"));
  }

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    if (!existsSync(data.typeFilePath)) {
      console.log(chalk.red("类型不存在"));
    }
  }

  if (!existsSync(data.styleFilePath)) {
    console.log(chalk.red("样式不存在"));
  }

  if (!existsSync(data.exampleFilePath)) {
    console.log(chalk.red("示例不存在"));
  }

  const { delComponent } = await prompts({
    type: "confirm",
    name: "delComponent",
    message: `确认删除${data.componentDirPath}吗`,
  });

  if (!delComponent) {
    throw new Error("取消删除");
  }

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    const { delType } = await prompts({
      type: "confirm",
      name: "delType",
      message: `确认删除${data.typeFilePath}吗`,
    });

    if (!delType) {
      throw new Error("取消删除");
    }
  }

  const { delStyle } = await prompts({
    type: "confirm",
    name: "delStyle",
    message: `确认删除${data.styleFilePath}吗`,
  });

  if (!delStyle) {
    throw new Error("取消删除");
  }
  const { delExample } = await prompts({
    type: "confirm",
    name: "delExample",
    message: `确认删除${data.exampleDirPath}吗`,
  });

  if (!delExample) {
    throw new Error("取消删除");
  }

  rmSync(data.componentDirPath, { recursive: true, force: true });

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    rmSync(data.typeFilePath);
  }

  rmSync(data.styleFilePath);

  rmSync(data.exampleDirPath, { recursive: true, force: true });

  if (!existsSync(data.componentEntryFilePath)) {
    console.log(chalk.red("组件入口不存在"));
  } else {
    const content = readFileSync(data.componentEntryFilePath, "utf-8");

    writeFileSync(
      data.componentEntryFilePath,
      content.replace(data.componentEntryFileAddContent, ""),
    );
  }

  // 使用 useTypeDir 选项时，才判断
  if (useTypeDir) {
    if (!existsSync(data.typeEntryFilePath)) {
      console.log(chalk.red("类型入口不存在"));
    } else {
      const content = readFileSync(data.typeEntryFilePath, "utf-8");

      writeFileSync(
        data.typeEntryFilePath,
        content.replace(data.typeEntryFileAddContent, ""),
      );
    }
  }

  if (!existsSync(data.styleEntryFilePath)) {
    console.log(chalk.red("样式入口不存在"));
  } else {
    const content = readFileSync(data.styleEntryFilePath, "utf-8");

    writeFileSync(
      data.styleEntryFilePath,
      content.replace(data.styleEntryFileAddContent, ""),
    );
  }

  if (!existsSync(data.styleVarFilePath)) {
    console.log(chalk.red("样式变量不存在"));
  } else {
    const content = readFileSync(data.styleVarFilePath, "utf-8");

    writeFileSync(
      data.styleVarFilePath,
      content.replace(data.styleVarFileAddContent, ""),
    );
  }

  if (!existsSync(data.exampleEntryFilePath)) {
    console.log(chalk.red("示例入口不存在"));
  } else {
    const content = readFileSync(data.exampleEntryFilePath, "utf-8");

    writeFileSync(
      data.exampleEntryFilePath,
      content.replace(data.exampleEntryFileAddContent, ""),
    );
  }

  console.log(chalk.green("删除成功"));
};

export const handler = async (cmd: ChildCmd, argv: ArgumentsCamelCase) => {
  // console.log("cmd:", cmd);
  // console.log("argv:", argv);

  const configInfo = getConfig();

  // console.log("configInfo:", configInfo);

  const src = await getSrc(configInfo);

  // console.log("src:", src);

  if (cmd === "add") {
    await dealAdd({ argv, configInfo, src });
  } else if (cmd === "remove") {
    await dealRemove({ argv, configInfo, src });
  } else {
    throw new Error(`未知命令${cmd}`);
  }
};
